/**************************************************************************
Step 1. Include necessary header files such that the stuff your test logic needs is declared. 
Don't forget gtest.h, which declares the testing framework.                                                   
**************************************************************************/
#include "gtest/gtest.h"
#include "include/pf_util.h"
#include "include/pf_internal.h"

#define IS_64bit() (sizeof(long) == 8)
#define IS_32bit() (sizeof(long) == 4)

int g_i = 0;

typedef struct mask_result
{
    char* mybuf;
    int sleep_second;
}mask_result_t;

void* thread_sig_mask_block(void* param)
{
    PF_UNUSED(param);
    pf_sig_mask(PF_ON,2,SIGALRM,SIGINT);

    g_i = 0;
    while(g_i < 5)
    {
        sleep(1);
        g_i++;
    }

    void* mybuf = strdup("block_finish");
    return mybuf;
}
void* thread_sig_mask_unblock(void* param)
{
    PF_UNUSED(param);
    pf_sig_mask(PF_OFF,2,SIGALRM,SIGINT);

    g_i = 0;
    while(g_i < 5)
    {
        sleep(1);
        g_i++;
    }

    void* mybuf = strdup("unblock_finish");
    return mybuf;
}
void sighand(int signo)
{
    PF_UNUSED(signo);
    g_i = 10;
    return;
}


/**************************************************************************
Step 2. Use test fixture to design your complex cases. 
You can add SetUp() to initialize the test data and 
TearDown() to clear the test data for common usage
Pls remember that when you using test fixture, need to use macro "TEST_F" instead of "TEST"                                                 
**************************************************************************/
class PfUtilTest : public testing::Test 
{
    /* This SetUp() will be called before every TEST CASE which is marked by macro "TEST_F" */
    virtual void SetUp() 
    {

    }

    /* This TearDown will be called after every TEST CASE which is marked by macro "TEST_F" */
    virtual void TearDown() 
    {

    }

};

/***************************************************************************
Step 3. Use macro "TEST_F" to start your test case                                      
You can design your test case as the example
***************************************************************************/
TEST_F(PfUtilTest, pf_get_time_tick)
{
}

TEST_F(PfUtilTest, pf_get_time_diff_sec)
{
    struct timespec begintime;
    begintime.tv_sec = 100;
    begintime.tv_nsec = 123456789;
    struct timespec endtime ;
    endtime.tv_sec = 101;
    endtime.tv_nsec = 12345678;

    double seconds = endtime.tv_sec - begintime.tv_sec + (endtime.tv_nsec - begintime.tv_nsec)*0.000000001;
    double pf_seconds = pf_get_time_diff_sec(&begintime,&endtime);
    EXPECT_DOUBLE_EQ(pf_seconds,seconds);

    endtime.tv_sec = 99;
    seconds = endtime.tv_sec - begintime.tv_sec + (endtime.tv_nsec - begintime.tv_nsec)*0.000000001;
    pf_seconds = pf_get_time_diff_sec(&begintime,&endtime);
    EXPECT_DOUBLE_EQ(pf_seconds,seconds);

    /*
    endtime.tv_nsec = 999456789;
    seconds = endtime.tv_sec - begintime.tv_sec + (endtime.tv_nsec - begintime.tv_nsec)*0.000000001;
    pf_seconds = pf_get_time_diff_sec(&begintime,&endtime);
    EXPECT_DOUBLE_EQ(pf_seconds,seconds);
    */

}

TEST_F(PfUtilTest, pf_get_time_diff_nsec)
{
    struct timespec begintime ;
    begintime.tv_sec = 100;
    begintime.tv_nsec = 123456789;
    struct timespec endtime ;
    endtime.tv_sec = 101;
    endtime.tv_nsec = 12345678;

    int64_t nanoseconds = (endtime.tv_sec - begintime.tv_sec)*1000000000 + (endtime.tv_nsec - begintime.tv_nsec);
    int64_t pf_nanoseconds = pf_get_time_diff_nsec(&begintime,&endtime);
    EXPECT_EQ(pf_nanoseconds,nanoseconds);

    endtime.tv_sec = 99;
    nanoseconds = (endtime.tv_sec - begintime.tv_sec)*1000000000 + (endtime.tv_nsec - begintime.tv_nsec);
    pf_nanoseconds = pf_get_time_diff_nsec(&begintime,&endtime);
    EXPECT_EQ(pf_nanoseconds,nanoseconds);

    endtime.tv_nsec = 999999999;
    nanoseconds = (endtime.tv_sec - begintime.tv_sec)*1000000000 + (endtime.tv_nsec - begintime.tv_nsec);
    pf_nanoseconds = pf_get_time_diff_nsec(&begintime,&endtime);
    EXPECT_EQ(pf_nanoseconds,nanoseconds);

}

TEST_F(PfUtilTest, pf_get_abs_time)
{

}

TEST_F(PfUtilTest, pf_get_rel_time)
{
}

TEST_F(PfUtilTest, pf_rand)
{
}

TEST_F(PfUtilTest, pf_mkdir)
{
    const char* dir1 = "aa";
    const char* dir2 = "aa/bb/cc/dd";
    const char* dir3 = "aa/bb";
    const char* dir4 = "aa/bb/cc/kk";
    const char* dir5 = "aa/bb/cc/dd";
    const char* dir6 = "aa/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc/bb/cc/dd/bb/cc/dd/bb/cc/dd/bb/cc";
    const char* dir7 = "aa/bb/cc/dd/gg";
    const char* dir8 = "aa/bb/cc/dd/gg/hh";


    int ret1 = pf_mkdir(dir1,0777);
    EXPECT_EQ(ret1,0);

    int ret2 = pf_mkdir(dir2,0771);
    EXPECT_EQ(ret2,0);

    int ret3 = pf_mkdir(dir3,0777);
    EXPECT_EQ(ret3,0);
    
    int ret4 = pf_mkdir(dir4,0777);
    EXPECT_EQ(ret4,0);

    int ret5 = pf_mkdir(dir5,0771);
    EXPECT_EQ(ret5,0); 

    int ret6 = pf_mkdir(dir6,0771); 
    EXPECT_EQ(ret6,0); 

    int ret7 = pf_mkdir(dir7,0000);
    EXPECT_EQ(ret7,0);

    int ret8 = pf_mkdir(dir8,0777); 
    EXPECT_NE(ret8,0);

    chmod(dir7,0777);
    system("rm -r aa");
}

TEST_F(PfUtilTest, pf_gettid)
{
    int pid = pf_gettid();
    int mypid = 0;
    if (IS_64bit())
    {
        mypid = syscall(186);
    }
    else
    {
        mypid = syscall(224);
    }
    EXPECT_EQ(pid, mypid);
}

TEST_F(PfUtilTest, pf_daemon)
{
}

TEST_F(PfUtilTest, pf_sig_mask)
{
    struct sigaction        actions;
    memset(&actions, 0, sizeof(actions)); 
    sigemptyset(&actions.sa_mask);  
    actions.sa_flags = 0;
    actions.sa_handler = sighand; 

    sigaction(SIGALRM,&actions,NULL);
    sigaction(SIGINT,&actions,NULL);


    pthread_t mythread;
    int tmp = 0;
    tmp = pthread_create(&mythread, NULL, thread_sig_mask_block, NULL);
    EXPECT_EQ(tmp, 0);
    sleep(2);
    tmp = pthread_kill(mythread, SIGALRM); 
    EXPECT_EQ(tmp, 0);
    void* p_value = NULL;
    pthread_join(mythread, &p_value);
    EXPECT_STREQ((char*)p_value,"block_finish");
    EXPECT_EQ(g_i,5);
    free(p_value);

    tmp = pthread_create(&mythread, NULL, thread_sig_mask_unblock, NULL);
    EXPECT_EQ(tmp, 0);
    sleep(2);
    tmp = pthread_kill(mythread, SIGALRM);
    EXPECT_EQ(tmp, 0);
    p_value = NULL;
    pthread_join(mythread, &p_value);
    EXPECT_STREQ((char*)p_value,"unblock_finish");
    EXPECT_EQ(g_i,11);
    free(p_value);

    tmp = pthread_create(&mythread, NULL, thread_sig_mask_block, NULL);
    EXPECT_EQ(tmp, 0);
    sleep(2);
    tmp = pthread_kill(mythread, SIGINT);
    EXPECT_EQ(tmp, 0);
    p_value = NULL;
    pthread_join(mythread, &p_value);
    EXPECT_STREQ((char*)p_value,"block_finish");
    EXPECT_EQ(g_i,5);
    free(p_value);

    tmp = pthread_create(&mythread, NULL, thread_sig_mask_unblock, NULL);
    EXPECT_EQ(tmp, 0);
    sleep(2);
    tmp = pthread_kill(mythread, SIGINT);
    EXPECT_EQ(tmp, 0);
    p_value = NULL;
    pthread_join(mythread, &p_value);
    EXPECT_STREQ((char*)p_value,"unblock_finish");
    EXPECT_EQ(g_i,11);
    free(p_value);

    int ret = pf_sig_mask(PF_INVALID,2,SIGALRM,SIGINT);
    EXPECT_EQ(ret, PF_EINVAL);
}

TEST_F(PfUtilTest, pf_sleep)
{
}

TEST_F(PfUtilTest, pf_self_path)
{
    char buff[100] = {0};
    //getcwd(buff,sizeof(buff));

    //strncpy(buff+strlen(buff),"/.libs/lt-test_app",18);
    readlink("/proc/self/exe", buff, sizeof(buff));
    const char* exec_path = pf_self_path();
    EXPECT_STREQ(exec_path,buff);
}
